/*
* INSANE - Interactive Structural Analysis Environment
*
* Copyright (C) 2003-2005
* Universidade Federal de Minas Gerais
* Escola de Engenharia
* Departamento de Engenharia de Estruturas
* 
* Author's email :    insane@dees.ufmg.br
* Author's website :  http://www.dees.ufmg.br/insane
* 
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or any later version.
* 
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
* 
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/
package br.ufmg.dees.insane.model.disc.driver;

import java.util.ArrayList;
import java.util.ListIterator;

import br.ufmg.dees.insane.model.disc.analysismodel.AnalysisModel;
import br.ufmg.dees.insane.model.disc.element.Element;
import br.ufmg.dees.insane.model.disc.fem.FemModel;
import br.ufmg.dees.insane.model.disc.node.Node;
import br.ufmg.dees.insane.util.IMatrix;
import br.ufmg.dees.insane.util.IVector;
import br.ufmg.dees.insane.util.LinearEquationSystems;
import br.ufmg.dees.insane.util.SingularMatrixException;

/**
*A class representing a driver for a structural mech problem.
*
*@author Fonseca, Flavio & Pitangueira, Roque
*@version 1.0
*@since September 2003
*@see model.discrete.node
*@see model.discrete.analysismodel
*@see model.discrete.femmodel
*@see model.discrete.element
*/

public class StructuralMech implements Driver {
	
	/**The FemModel of this Driver.*/
	private FemModel myModel;
	
	private LinearEquationSystems sel = new LinearEquationSystems();
	
 
	/** Returns the myModel of this Driver.
	*@return The myModel of this Driver.
	*/
	public FemModel getFemModel() {
		return (myModel);
	};	
	
	/** Sets the FemModel of this Driver.
	*@param a The FemModel of this Driver.
	*/
	public void setFemModel(FemModel a){
		myModel = a;
	}
 
	/** Returns the stiffness matrix of this Driver's FemModel just with the elements necessary to calculate the reactions.
	*@return The stiffness matrix of this Driver's FemModel just with the elements necessary to calculate the reactions.
	*Cpu
	*/
	public IMatrix reactionsStiffnessMatrix()
	{
		Element element;
		int numRestraints = myModel.getNumberOfRestraints();
		int numEquations = myModel.getNumberOfEquations();
		IMatrix k = new IMatrix(numRestraints, numEquations);
		k.setZero();
		ListIterator elements = myModel.getElementsList().listIterator();
		while (elements.hasNext())
		{
			element = (Element) elements.next();
			
			//Adding elements' stiffness matrix to model's stiffness matrix
			IMatrix kLocal = element.globalStiffnessMatrix();
			int elmNumNodes = element.getIncidence().size();
			for (int i=0; i<elmNumNodes*element.getAnalysisModel().getNdf(); i++)
			{
				for (int j=0; j<elmNumNodes*element.getAnalysisModel().getNdf(); j++)
				{
					int a = element.getReducedEquation(i);
					int b = element.getReducedEquation(j);
					if (a<0 && b>0)
					{
						k.setElement(-a-1, b-1, k.getElement(-a-1, b-1) + kLocal.getElement(i, j));
					};
				};
			};
		};
		
		return(k);
	};
	
 
	
	/** Returns the stiffness matrix of this Driver's FemModel just with the elements necessary to calculate the equivalent nodal force vector of the prescribed displacement.
	*@return The stiffness matrix of this Driver's FemModel just with the elements necessary to calculate the equivalent nodal force vector of the prescribed displacement.
	*Cpp
	*/
	public IMatrix preDispStiffnessMatrix(){
		Element element;
		int numRestraints = myModel.getNumberOfRestraints();
		IMatrix k = new IMatrix(numRestraints, numRestraints);
		k.setZero();
		ListIterator elements = myModel.getElementsList().listIterator();
		while (elements.hasNext()) {
			element = (Element) elements.next();
			
			//Adding elements' stiffness matrix to model's stiffness matrix
			IMatrix kLocal = element.globalStiffnessMatrix();
			for (int i=0; i<kLocal.getNumRow(); i++){
				for (int j=0; j<kLocal.getNumCol(); j++){
					int a = element.getReducedEquation(i);
					int b = element.getReducedEquation(j);
					if (a<0 && b<0){
						k.setElement(-a-1, -b-1, k.getElement(-a-1, -b-1) + kLocal.getElement(i, j));
					};
				};
			};
		};
		
		return(k);
	};
	
 
	
	/** Returns the reduced stiffness matrix of this Driver's FemModel.
	*@return The reduced stiffness matrix of this Driver's FemModel.
	*Cuu
	*/
	public IMatrix reducedStiffnessMatrix(){
		
		//IMatrix kr = new IMatrix(3,3);
		
		Element element;
		Node node;
		int numEquations = myModel.getNumberOfEquations();
		IMatrix kr = new IMatrix(numEquations, numEquations);
		kr.setZero();
		ListIterator elements = myModel.getElementsList().listIterator();
		while (elements.hasNext()) {
			element = (Element) elements.next();
			
			//Adding elements' stiffness matrix to model's stiffness matrix
			IMatrix kLocal = element.globalStiffnessMatrix();
			int elmNumNodes = element.getIncidence().size();
			for (int i=0; i<elmNumNodes*element.getAnalysisModel().getNdf(); i++){
				for (int j=0; j<elmNumNodes*element.getAnalysisModel().getNdf(); j++){
					int a = element.getReducedEquation(i);
					int b = element.getReducedEquation(j);
					if (a>0 && b>0){
						kr.setElement(a-1, b-1, kr.getElement(a-1, b-1) + kLocal.getElement(i, j));
					};
				};
			};
		};
		
		//Adding nodal stiffness to model's stiffness matrix
		ListIterator nodes = myModel.getNodesList().listIterator();
		AnalysisModel anl = myModel.getGlobalAnalysisModel();
		int pos;
		while (nodes.hasNext()) {
			node = (Node) nodes.next();
			for (int i=0; i<6; i++) {
				if (anl.getValidEquation(i)) {
					pos = node.getEquation(i);
					if (pos > 0) {
						kr.setElement(pos-1, pos-1, kr.getElement(pos-1, pos-1) + node.getSpring(i));
					};
				};
			};
		};
		
		return(kr);
	};
	

	
	/** Returns the reduced stiffness matrix of this Driver's FemModel.
	*@return The full stiffness matrix of this Driver's FemModel.
	*Cuu
	*/
	public IMatrix fullStiffnessMatrix(){
		this.numberAllNodeEquations();
		this.numberElementEquations();
		this.reduceEquationsVector();
		Element element;
		Node node;
		int numEquations = myModel.getNumberOfEquations();
		IMatrix kr = new IMatrix(numEquations, numEquations);
		kr.setZero();
		ListIterator elements = myModel.getElementsList().listIterator();
		while (elements.hasNext()) {
			element = (Element) elements.next();
			IMatrix kLocal = element.globalStiffnessMatrix();
			int elmNumNodes = element.getIncidence().size();
			for (int i=0; i<elmNumNodes*element.getAnalysisModel().getNdf(); i++){
				for (int j=0; j<elmNumNodes*element.getAnalysisModel().getNdf(); j++){
					int a = element.getReducedEquation(i);
					int b = element.getReducedEquation(j);
					if (a>0 && b>0){
						kr.setElement(a-1, b-1, kr.getElement(a-1, b-1) + kLocal.getElement(i, j));
					};
				};
			};
		};
		
		//Adding nodal stiffness to model's stiffness matrix
		ListIterator nodes = myModel.getNodesList().listIterator();
		AnalysisModel anl = myModel.getGlobalAnalysisModel();
		int pos;
		while (nodes.hasNext()) {
			node = (Node) nodes.next();
			for (int i=0; i<6; i++) {
				if (anl.getValidEquation(i)) {
					pos = node.getEquation(i);
					if (pos > 0) {
						kr.setElement(pos-1, pos-1, kr.getElement(pos-1, pos-1) + node.getSpring(i));
					};
				};
			};
		};
		this.numberNodeEquations();
		this.numberElementEquations();
		this.reduceEquationsVector();
		return(kr);
	};
	
	
	
	/** Returns the reduced nodal force vector of this Driver's FemModel.<p>
	* The data is stored in the same order of equations.<br>
	*Ex.: F[0] is related to equation 1.
	*@return The reduced nodal force vector of this Driver's FemModel.
	*Np
	*/
	public IVector reducedNodalForceVector(){
		int numEquations = myModel.getNumberOfEquations();
		IVector pr = new IVector(numEquations);
		Node node;
		ListIterator nodes = myModel.getNodesList().listIterator();
		while (nodes.hasNext()) {
			node = (Node) nodes.next();
			for (int i=0; i<6; i++){
				if (node.getEquation(i) > 0) {
					pr.setElement(node.getEquation(i)-1, pr.getElement(node.getEquation(i)-1) + node.getForce(i));
				};
			};
		};
		return (pr);
	};
	
 
	
	/** Returns the reactions nodal force vector of this Driver's FemModel.<p>
	* The data is stored in the same order of equations.<br>
	*Ex.: F[0] is related to equation 1.
	*@return The reactions nodal force vector of this Driver's FemModel.
	*Ru
	*/
	public IVector reactionsNodalForceVector(){
		int numRestraints = myModel.getNumberOfRestraints();
		IVector pr = new IVector(numRestraints);
		Node node;
		ListIterator nodes = myModel.getNodesList().listIterator();
		
		while (nodes.hasNext()) {
			node = (Node) nodes.next();
			for (int i=0; i<6; i++){
				if (node.getEquation(i) < 0) {
					pr.setElement(-node.getEquation(i)-1, pr.getElement(-node.getEquation(i)-1) + node.getForce(i));
				};
			};
		};
		return (pr);
	};
	
 
	
	/** Returns the reduced equivalent nodal force vector of this Driver's FemModel.<p>
	* The data is stored in the same order of equations.<br>
	*Ex.: F[0] is related to equation 1.
	*@return The reduced equivalent nodal force vector of this Driver's FemModel.
	*Ep
	*/
	public IVector reducedEquivalentForceVector(){
		Element element;
		int numEquations = myModel.getNumberOfEquations();
		IVector efv = new IVector(numEquations);
		efv.zero();
		ListIterator elements = myModel.getElementsList().listIterator();
		
		while (elements.hasNext()) {
			element = (Element) elements.next();
			
			//Adding elements' equivalent force vector to model's equivalent force vector
			IVector efvLocal = element.globalEquivalentForceVector();
			int elmNumNodes = element.getIncidence().size();
			for (int i=0; i<elmNumNodes*element.getAnalysisModel().getNdf(); i++){
					int a = element.getReducedEquation(i);
					if (a>0){
						efv.setElement(a-1, efv.getElement(a-1) + efvLocal.getElement(i));
					};
			};
		};
		return(efv);
	};
	
	/** Returns the full equivalent nodal force vector of this Driver's FemModel.<p>
	* The data is stored in the same order of equations.<br>
	*Ex.: F[0] is related to equation 1.
	*@return The reduced equivalent nodal force vector of this Driver's FemModel.
	*Ep
	*/
	public IVector fullEquivalentForceVector(){
		this.numberAllNodeEquations();
		this.numberElementEquations();
		this.reduceEquationsVector();
		Element element;
		Node node;
		int numEquations = myModel.getNumberOfEquations();
		IVector fr = new IVector(numEquations);
		fr.zero();
		ListIterator elements = myModel.getElementsList().listIterator();
		while (elements.hasNext()) {
			element = (Element) elements.next();
			IVector fLocal = element.globalEquivalentForceVector();
			int elmNumNodes = element.getIncidence().size();
			for (int i=0; i<elmNumNodes*element.getAnalysisModel().getNdf(); i++){
				int a = element.getReducedEquation(i);
					if (a>0){
						fr.setElement(a-1, fr.getElement(a-1) + fLocal.getElement(i));
					};
				};
			};
	    //Adding nodal forces to model's forces matrix
		ListIterator nodes = myModel.getNodesList().listIterator();
		AnalysisModel anl = myModel.getGlobalAnalysisModel();
		int pos;
		while (nodes.hasNext()) {
			node = (Node) nodes.next();
			for (int i=0; i<6; i++) {
				if (anl.getValidEquation(i)) {
					pos = node.getEquation(i);
					if (pos > 0) {
						fr.setElement(pos-1, fr.getElement(pos-1) + node.getSpring(i));
					};
				};
			};
		};
		this.numberNodeEquations();
		this.numberElementEquations();
		this.reduceEquationsVector();
		return(fr);
	};

 
	
	/** Sets the specified displacements to their Nodes.<p>
	* The data in input vector must be stored in the same order of equations.<br>
	*Ex.: F[0] is related to equation 1.
	*@param reducedDisplacementVector A IVector containing the displacements.
	*setXu
	*/
	public void assignKinematicState(IVector reducedDisplacementVector){
		Node node;
		ListIterator nodes = myModel.getNodesList().listIterator();
		while (nodes.hasNext()){
			node = (Node) nodes.next();
			for (int i=0; i<6; i++){
				if (node.getEquation(i) > 0)
					node.setDisplacement(i, reducedDisplacementVector.getElement(node.getEquation(i)-1));
			};
		};
	};
	
 
	
	/** Sets the specified force to their Nodes.<p>
	* The data in input vector must be stored in the same order of equations.<br>
	*Ex.: F[0] is related to equation -1.
	*@param forceVector A IVector containing the forces.
	*setRu
	*/
	public void assignStaticState(IVector forceVector)
	{
		Node node;
		ListIterator nodes = myModel.getNodesList().listIterator();
		while (nodes.hasNext())
		{
			node = (Node) nodes.next();
			for (int i=0; i<6; i++)
			{
				if (node.getEquation(i) < 0)
					node.setReaction(i, forceVector.getElement(node.getEquation(i)*-1-1));
			};
		};
	};

 
	
	/** Numbers the equations of the Nodes.<p>
	*Positive numbers are related to possible displacements.<br>
	*Negative numbers are related to restraints to that displacement.<br>
	*Zero is related to invalid displacement to that type of AnalysisModel.
	*numberEquation
	*/
	public void numberNodeEquations(){
		myModel.setNumberOfEquations(0);
		myModel.setNumberOfRestraints(0);
		Node node;
		ListIterator nodes = myModel.getNodesList().listIterator();
		while (nodes.hasNext()) {
			node = (Node)nodes.next();
			for (int i=0; i<6; i++){
				if (myModel.getGlobalAnalysisModel().getValidEquation(i)) {
					if (!node.getRestraint(i) ){
						myModel.setNumberOfEquations(myModel.getNumberOfEquations()+1);
						node.setEquation(i, myModel.getNumberOfEquations());
					}
					else {
						myModel.setNumberOfRestraints(myModel.getNumberOfRestraints()+1);
						node.setEquation(i, -myModel.getNumberOfRestraints());
					};
				} else {
					node.setEquation(i, 0);
				}
			};
		};
	};
	
	
	/** Numbers the equations of the Nodes.<p>
	*Positive numbers are related to possible displacements.<br>
	*Negative numbers are related to restraints to that displacement.<br>
	*Zero is related to invalid displacement to that type of AnalysisModel.
	*numberEquation
	*/
	public int[] getNodeEquations(){
		Node node;
		int [] eqs = new int[this.getNumberOfEquations()+myModel.getNumberOfRestraints()];
		
		ListIterator nodes = myModel.getNodesList().listIterator();
		int cont = 0;
		while (nodes.hasNext()) {
			node = (Node)nodes.next();
			for (int i=0; i<6; i++){
				if (myModel.getGlobalAnalysisModel().getValidEquation(i)) {
					eqs[cont] = node.getEquation(i);
					cont++;
				}
			};
		};
		return eqs;
	};
	
//	********************************************************************************
	
	public void zeroNodeEquations(){
		myModel.setNumberOfEquations(0);
		Node node;
		ListIterator nodes = myModel.getNodesList().listIterator();
		while (nodes.hasNext()) {
			node = (Node)nodes.next();
			for (int i=0; i<6; i++){
				if (myModel.getGlobalAnalysisModel().getValidEquation(i)) {
					if (!node.getRestraint(i) ){
						myModel.setNumberOfEquations(myModel.getNumberOfEquations()+1);
						node.setEquation(i, 0);
					}
					else {
						myModel.setNumberOfRestraints(myModel.getNumberOfRestraints()+1);
						node.setEquation(i, 0);
					};
				} else {
					node.setEquation(i, 0);
				}
			};
		};
	};
	
	
//	********************************************************************************
	
	/** Numbers all the equations of the Nodes.<p>
	*numberEquation
	*/
	public void numberAllNodeEquations(){
		myModel.setNumberOfEquations(0);
		Node node;
		ListIterator nodes = myModel.getNodesList().listIterator();
		while (nodes.hasNext()) {
			node = (Node)nodes.next();
			for (int i=0; i<6; i++){
				if (myModel.getGlobalAnalysisModel().getValidEquation(i)) {
						myModel.setNumberOfEquations(myModel.getNumberOfEquations()+1);
						node.setEquation(i, myModel.getNumberOfEquations());
				} else {
					node.setEquation(i, 0);
				}
			};
		};
	};
	
	
//	********************************************************************************
	
	/** Init the equations of the Nodes as zero.<p>
	 * 
	*/
	public void initEquations(){
		myModel.setNumberOfEquations(0);
		Node node;
		ListIterator nodes = myModel.getNodesList().listIterator();
		while (nodes.hasNext()) {
			node = (Node)nodes.next();
			for (int i=0; i<6; i++){
			    node.setEquation(i, 0);
			}
		};
	};
	
 	/** Numbers the equations of one Node.<p>
	*Positive numbers are related to possible displacements.<br>
	*Negative numbers are related to restraints to that displacement.<br>
	*Zero is related to invalid displacement to that type of AnalysisModel.
	*numberEquations(Node node)
	*/
	public void numberOneNodeEquations(Node node){
		myModel.setNumberOfEquations(0);
			for (int i=0; i<6; i++){
				if (myModel.getGlobalAnalysisModel().getValidEquation(i)) {
					if (!node.getRestraint(i) ){
						myModel.setNumberOfEquations(myModel.getNumberOfEquations()+1);
						node.setEquation(i, myModel.getNumberOfEquations());
					}
					else {
						myModel.setNumberOfRestraints(myModel.getNumberOfRestraints()+1);
						node.setEquation(i, -myModel.getNumberOfRestraints());
					};
				} else {
					node.setEquation(i, 0);
				}
			};
		};
	
//		********************************************************************************
		
		/** Numbers the equations of the new Nodes List.<p>
		*Positive numbers are related to possible displacements.<br>
		*Negative numbers are related to restraints to that displacement.<br>
		*Zero is related to invalid displacement to that type of AnalysisModel.
		*numberEquations(ArrayList nodesList)
		*/
		public void numberNodeByNodeEquations(ArrayList nodesList){
			myModel.setNumberOfEquations(0);
			Node node, modelNode;
			ListIterator nodes = nodesList.listIterator();
			while (nodes.hasNext()) {
				node = (Node)nodes.next();
				for (int i=0; i<6; i++){
					if (myModel.getGlobalAnalysisModel().getValidEquation(i)) {
						if (!node.getRestraint(i) ){
							myModel.setNumberOfEquations(myModel.getNumberOfEquations()+1);
							node.setEquation(i, myModel.getNumberOfEquations());
						}
						else {
							myModel.setNumberOfRestraints(myModel.getNumberOfRestraints()+1);
							node.setEquation(i, -myModel.getNumberOfRestraints());
						};
					} else {
						node.setEquation(i, 0);
					}
				};
			};
			
			ListIterator modelNodes = myModel.getNodesList().listIterator();
			while (modelNodes.hasNext()) {
				modelNode = (Node)modelNodes.next();
				for (int i=0; i<6; i++){
					if(modelNode.getEquation(i)<=0){
						if (myModel.getGlobalAnalysisModel().getValidEquation(i)) {
							if (!modelNode.getRestraint(i) ){
								myModel.setNumberOfEquations(myModel.getNumberOfEquations()+1);
								modelNode.setEquation(i, myModel.getNumberOfEquations());
							}
							else {
								myModel.setNumberOfRestraints(myModel.getNumberOfRestraints()+1);
								modelNode.setEquation(i, -myModel.getNumberOfRestraints());
							};
						} else {
							modelNode.setEquation(i, 0);
						}
					};
				};
			
			}
			
			
		};	
		
		
 	
		
	/** Numbers the equations of the Elements.<p>
	*<b><i>Method numberNodeEquations() must have been previously called.</i></b><p>
	*Positive numbers are related to possible displacements.<br>
	*Negative numbers are related to restraints to that displacement.<br>
	*Zero is related to invalid displacement to that type of AnalysisModel.
	*@see #numberNodeEquations
	*/
	public void numberElementEquations(){
		Element element;
		Node node;
		ListIterator elements = myModel.getElementsList().listIterator();
		while (elements.hasNext()) {
			element = (Element) elements.next();
			ListIterator nodes = element.getIncidence().listIterator();
			int i=0;
			while (nodes.hasNext()) {
				node = (Node) nodes.next();
				for (int j=0; j<6; j++) {
					element.setEquation(j+6*i, node.getEquation(j));
				};
			i++;
			};
		};
	};

 
	
	/** Returns the reduced displacement vector of this Driver's FemModel.<p>
	* The data is stored in the same order of equations.<br>
	*Ex.: D[0] is related to equation 1.
	*@return The reduced displacement vector of this Driver's FemModel.
	*getXu
	*/
	public IVector reducedDisplacementVector() {
		IVector aux = new IVector (myModel.getNumberOfEquations());
		Node node;
		ListIterator nodes = myModel.getNodesList().listIterator();
		int j = 0;
		while (nodes.hasNext()) {
			node = (Node)nodes.next();
			for (int i=0; i<6; i++) {
				if (myModel.getGlobalAnalysisModel().getValidEquation(i) && node.getEquation(i)>0) {
					aux.setElement(j, node.getDisplacement(i));
					j++;
				};
			};
		};
		return (aux);
	};
	
 
	
	/** Reduces the equations vector of this Driver's FemModel's Elements, in way that it contains just the valid equations.<p>
	*<b><i>Method numberElementEquations() must have been previously called.</i></b><p>
	*@see #numberElementEquations
	*apagado
	*/
	public void reduceEquationsVector() {
		
		Element element;
		ListIterator elements = myModel.getElementsList().listIterator();
		while (elements.hasNext()) {
			element = (Element) elements.next();
			int elmNumNodes = element.getIncidence().size();
			int[] redEq = new int[elmNumNodes*element.getAnalysisModel().getNdf()];
			int z=0;
			
			int n = 0;
			ListIterator nodes = element.getIncidence().listIterator();
			while(nodes.hasNext()) {
				nodes.next();
				for (int i=0; i<6; i++) {
					if (element.getAnalysisModel().getValidEquation(i)) {
						redEq[z] = element.getEquation(i+6*n);
						z++;
					}
				}
				n++;
			}
			element.setReducedEquations(redEq);
		};
	};
	
public int [] EquationsVector() {
	    int [] eV = new int[this.fullEquivalentForceVector().getSize()];
		Element element;
		ListIterator elements = myModel.getElementsList().listIterator();
		int cont=0;
		while (elements.hasNext()) {
			element = (Element) elements.next();
			for (int i=0; i<element.getReducedEquation().length; i++)
			eV[cont]=element.getReducedEquation(i);
			cont ++;
		};
		return eV;
	};
	/** Returns the equivalent nodal force vector necessary to calculate the ractions.
	*@return The equivalent nodal force vector necessary to calculate the ractions.
	*getEu
	*/
	public IVector reactionsEquivalentForceVector()
	{
		Element element;
		int numRestraints = myModel.getNumberOfRestraints();
		IVector refv = new IVector(numRestraints);
		ListIterator elements = myModel.getElementsList().listIterator();
		while (elements.hasNext())
		{
			element = (Element) elements.next();
			
			//Adding elements' stiffness matrix to model's stiffness matrix
			IVector efvLocal = element.globalEquivalentForceVector();
			for (int i=0; i<efvLocal.getSize(); i++)
			{
				int a = element.getReducedEquation(i);
				if (a<0)
				{
					refv.setElement(-a-1, refv.getElement(-a-1) + efvLocal.getElement(i));
				};
			};
		};
		return(refv);
	};
	
 
	
	/** Calculates the internal forces of all Elements.
	 * getF
	 * apagado
	 */
	public void calculateInternalForces() 
	{
		Element element;
		ListIterator elements = myModel.getElementsList().listIterator();
		while (elements.hasNext())
		{
			element = (Element) elements.next();
			element.internalForces();
		};
	};
	
 
	
	/** Returns the reduced prescribed displacements vector of this Driver's FemModel.<p>
	* The data is stored in the same order of equations.<br>
	*Ex.: F[0] is related to equation -1.
	*@return The reduced prescribed displacements vector of this Driver's FemModel.
	*getXp
	*/
	public IVector reducedPreDisplacementVector()
	{
		Node node;
		AnalysisModel anl = myModel.getGlobalAnalysisModel();
		int numRestraints = myModel.getNumberOfRestraints();
		IVector pdv = new IVector(numRestraints);
		ListIterator nodes = myModel.getNodesList().listIterator();
		while (nodes.hasNext())
		{
			node = (Node) nodes.next();
			//Storing nodes' equivalent force vector to model's prescribed displacements vector
			for (int i=0; i<6; i++)
			{
				int a = node.getEquation(i);
				if (a<0 && anl.getValidEquation(i))
				{
					pdv.setElement(-a-1, node.getPreDisplacement(i));
				};
			};
		};
		return(pdv);
	};
	
 
	
	/** Returns the reduced equivalent force vector for the prescribed displacements of this Driver's FemModel.<p>
	* The data is stored in the same order of equations.<br>
	*Ex.: F[0] is related to equation -1.
	*@return The reduced equivalent force vector for the prescribed displacements of this Driver's FemModel.
	*getCupXp
	*/
	public IVector reducedPreDisplacementEquivalentForceVector()
	{
		IMatrix kip = reactionsStiffnessMatrix();
		kip.transpose();
		IVector dp = reducedPreDisplacementVector();
		IVector fed = new IVector(kip.getNumRow());
		fed.mul(kip, dp);
		fed.negate();
		return (fed);
	};
	
 
	
	/** Returns the equivalent force vector for the prescribed displacements of this Driver's FemModel necessary to calculate the support reaction.<p>
	* The data is stored in the same order of equations.<br>
	*Ex.: F[0] is related to equation -1.
	*@return The equivalent force vector for the prescribed displacements of this Driver's FemModel necessary to calculate the support reaction.
	*getCppXp
	*/
	public IVector reactionsPreDisplacementEquivalentForceVector()
	{
		IMatrix kpp = preDispStiffnessMatrix();
		IVector dp = reducedPreDisplacementVector();
		IVector fed = new IVector (kpp.getNumRow());
		fed.mul(kpp, dp);
		return (fed);
	};
	
 
	
	/** Adds the value of the prescribed displacements to the calculated ones.
	 * setXp 
	 */
	public void addPrescribedDisplacements()
	{
		ListIterator nodes = myModel.getNodesList().listIterator();
		while (nodes.hasNext())
		{
			Node node = (Node) nodes.next();
			for (int i=0; i<6; i++)
			{
					node.setDisplacement(i, node.getDisplacement(i) + node.getPreDisplacement(i));
			};
		};
	}
	
 
	// Este m�todo provavelmente ir� desaparecer, Roque ir� decidir
	/**Analyses this Driver's FemModel, using this' Solution.*/
	public void analyseModel() throws SingularMatrixException
	{
		try 
		{
			numberNodeEquations();
			numberElementEquations();
			reduceEquationsVector();
			if (myModel.getNumberOfEquations()!=0) 
			{
				sel.setAMatrix(reducedStiffnessMatrix());
				sel.setBVector(reducedNodalForceVector());
				sel.addToBVector(reducedEquivalentForceVector());
				sel.addToBVector(reducedPreDisplacementEquivalentForceVector());
				sel.solverX();
				assignKinematicState(sel.getXVector());
			}
			else
			{
				sel.setBVector(new IVector(myModel.getNumberOfRestraints()));
			}
			sel.setAMatrix(reactionsStiffnessMatrix());
			sel.setXVector(reducedDisplacementVector());
			sel.solverB();
			sel.subFromBVector(reactionsEquivalentForceVector());
			sel.addToBVector(reactionsPreDisplacementEquivalentForceVector());
			sel.subFromBVector(reactionsNodalForceVector());
			assignStaticState(sel.getBVector());
			
			calculateInternalForces();
			addPrescribedDisplacements();
			
		} 
		catch (SingularMatrixException e)
		{
			throw (e);
		} 
		catch (Exception e1)
		{
			System.out.println("An exception occured during model analysis.");
			System.out.println(e1.getClass());
		}
	};
	 
	/** 
	 * 
	 *
	 *
	 */
public IVector getRVector()
{	
	IVector efv = reducedEquivalentForceVector();
	IVector pr = reducedNodalForceVector();
	IVector fed = reducedPreDisplacementEquivalentForceVector();
    int numEquations = myModel.getNumberOfEquations();
	IVector aux = new IVector(numEquations);
	aux.add(pr,fed);
	efv.add(aux);
	
	return (efv);		
}
 
/** Returns the reduced equivalent nodal force vector of this Driver's FemModel.<p>
* The data is stored in the same order of equations.<br>
*Ex.: F[0] is related to equation 1.
*@return The reduced equivalent nodal force vector of this Driver's FemModel.
*getFp
*/
public IVector getInternalRVector(){
	Element element;
	int numEquations = myModel.getNumberOfEquations();
	IVector efv = new IVector(numEquations);
	efv.zero();
	ListIterator elements = myModel.getElementsList().listIterator();
	
	while (elements.hasNext()) {
		element = (Element) elements.next();
		
		//Adding elements' equivalent force vector to model's equivalent force vector
		IVector efvLocal = element.internalForces();
		int elmNumNodes = element.getIncidence().size();
		for (int i=0; i<elmNumNodes*element.getAnalysisModel().getNdf(); i++){
				int a = element.getReducedEquation(i);
				if (a>0){
					efv.setElement(a-1, efv.getElement(a-1) + efvLocal.getElement(i));
				};
		};
	};
	return(efv);
};

 
public void updateState(){
    this.myModel.updateState();
}
 

//Este metodo � igual ao reducedStiffnessMatrix que est� acima nesta classe
//roque vai decidir qual nome vai ficar
/** Returns the reduced stiffness matrix of this Driver's FemModel.
*@return The reduced stiffness matrix of this Driver's FemModel.
*/
public IMatrix getTangentCMatrix(){
	
	//IMatrix kr = new IMatrix(3,3);
	
	Element element;
	Node node;
	int numEquations = myModel.getNumberOfEquations();
	IMatrix kr = new IMatrix(numEquations, numEquations);
	kr.setZero();
	ListIterator elements = myModel.getElementsList().listIterator();
	while (elements.hasNext()) {
		element = (Element) elements.next();
		
		//Adding elements' stiffness matrix to model's stiffness matrix
		IMatrix kLocal = element.globalStiffnessMatrix();
		int elmNumNodes = element.getIncidence().size();
		for (int i=0; i<elmNumNodes*element.getAnalysisModel().getNdf(); i++){
			for (int j=0; j<elmNumNodes*element.getAnalysisModel().getNdf(); j++){
				int a = element.getReducedEquation(i);
				int b = element.getReducedEquation(j);
				if (a>0 && b>0){
					kr.setElement(a-1, b-1, kr.getElement(a-1, b-1) + kLocal.getElement(i, j));
				};
			};
		};
	};
	
	//Adding nodal stiffness to model's stiffness matrix
	ListIterator nodes = myModel.getNodesList().listIterator();
	AnalysisModel anl = myModel.getGlobalAnalysisModel();
	int pos;
	while (nodes.hasNext()) {
		node = (Node) nodes.next();
		for (int i=0; i<6; i++) {
			if (anl.getValidEquation(i)) {
				pos = node.getEquation(i);
				if (pos > 0) {
					kr.setElement(pos-1, pos-1, kr.getElement(pos-1, pos-1) + node.getSpring(i));
				};
			};
		};
	};
	
	return(kr);
};  
 

// Este metodo � igual ao assignKinematicState que est� acima nesta classe
// roque vai decidir qual nome vai ficar
/** Sets the specified displacements to their Nodes.<p>
* The data in input vector must be stored in the same order of equations.<br>
*Ex.: F[0] is related to equation 1.
*@param reducedDisplacementVector A IVector containing the displacements.
*/
public void assignState(IVector reducedDisplacementVector){
	Node node;
	ListIterator nodes = myModel.getNodesList().listIterator();
	while (nodes.hasNext()){
		node = (Node) nodes.next();
		for (int i=0; i<6; i++){
			if (node.getEquation(i) > 0)
				node.setDisplacement(i, reducedDisplacementVector.getElement(node.getEquation(i)-1));
		};
	};
};

 
/** Returns the number of equations of FemModel.
*@return The number of equations of FemModel.
*/
public int getNumberOfEquations(){
	return(this.myModel.getNumberOfEquations());
};
}

